package org.pblue.tumblarity.view;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class UrlMappingFilter implements Filter {
  
  public static final String[] EXCLUDED_URL_SUFFIXES = new String[] {"ico","gif","css","js","jsp"};
  public static final String[] EXCLUDED_URI_COMPONENTS = new String[] {"controller","task","admin","_ah"};
  public static final String REQUEST_ATTR_COMPONENT_LIST = "componentlist";
  public static final String REQUEST_ATTR_COMPONENT  = "component";
  
  private Pattern mSuffixRegexPattern;
  private List<String> mExcludedUrlSuffixes;
  private List<String> mExcludedUriComponents;
  private Map<String,String> mUriComponentViews;
  private Map<String,RequestDispatcher> mRequestDispatchers;

  public void destroy() {
    // do nothing
  }

  public void doFilter(ServletRequest pRequest, ServletResponse pResponse, FilterChain pFilterChain) throws IOException, ServletException {
    if (!(pRequest instanceof HttpServletRequest) || !(pResponse instanceof HttpServletResponse)) {
      throw new ServletException("UrlMappingFilter supports HTTP requests only.");
    }
    
    HttpServletRequest httpRequest = (HttpServletRequest) pRequest;
    
    String suffix = "";
    Matcher propertyMatcher = getSuffixRegexPattern().matcher(httpRequest.getRequestURI());
    if (propertyMatcher.find()) {
      suffix = propertyMatcher.group(1);
    }
      
    if (!getExcludedUrlSuffixes().contains(suffix)) {
      List<String> uriComponents = new ArrayList<String>();
      String[] uri = httpRequest.getRequestURI().split("/");

      for (String uriFragment : uri) {
        if (uriFragment != null && !uriFragment.equals("")) {
          uriComponents.add(uriFragment);
        }
      }

      if (uriComponents.size() > 0) {
        String componentName = uriComponents.get(0);
        if (!getExcludedUriComponents().contains(componentName)) {
          pRequest.setAttribute(REQUEST_ATTR_COMPONENT_LIST, uriComponents);
          pRequest.setAttribute(REQUEST_ATTR_COMPONENT, componentName);
          RequestDispatcher rd = this.getRequestDispatchers().get(componentName);
          if (rd != null) {
            rd.forward(pRequest, pResponse);
            return;
          }          
        }
      } else {
        this.getRequestDispatchers().get("default").forward(pRequest, pResponse);
        return;
      }
    }
      
    pFilterChain.doFilter(pRequest, pResponse);
  }

  public void init(FilterConfig pFilterConfig) throws ServletException {
    // initialize suffix regex pattern
    this.setSuffixRegexPattern(Pattern.compile(".*\\.(.*)"));
    
    // initialize excluded url suffixes list
    this.setExcludedUrlSuffixes(Arrays.asList(EXCLUDED_URL_SUFFIXES));
    
    // initialize excluded uri components list
    this.setExcludedUriComponents(Arrays.asList(EXCLUDED_URI_COMPONENTS));
    
    // initialize uri component view map
    Map<String,String> uriComponentViews = new HashMap<String,String>();
    uriComponentViews.put( "followers" , "FollowersView" );
    this.setUriComponentViews(uriComponentViews);
    
    // initialize request dispatcher map
    Map<String,RequestDispatcher> requestDispatchers = new HashMap<String,RequestDispatcher>();
    for (String uriComponent : this.getUriComponentViews().keySet()) {
      requestDispatchers.put(uriComponent, pFilterConfig.getServletContext().getNamedDispatcher(this.getUriComponentViews().get(uriComponent)));
    }
    requestDispatchers.put("default", pFilterConfig.getServletContext().getNamedDispatcher("DefaultView"));
    this.setRequestDispatchers(requestDispatchers);
  }
  
  public Pattern getSuffixRegexPattern() {
    return mSuffixRegexPattern;
  }
  
  public void setSuffixRegexPattern(Pattern pSuffixRegexPattern) {
    mSuffixRegexPattern = pSuffixRegexPattern;
  }

  
  public List<String> getExcludedUrlSuffixes() {
    return mExcludedUrlSuffixes;
  }

  
  public void setExcludedUrlSuffixes(List<String> pExcludedUrlSuffixes) {
    mExcludedUrlSuffixes = pExcludedUrlSuffixes;
  }

  
  
  public List<String> getExcludedUriComponents() {
    return mExcludedUriComponents;
  }

  
  public void setExcludedUriComponents(List<String> pExcludedUriComponents) {
    mExcludedUriComponents = pExcludedUriComponents;
  }
  
  public Map<String, String> getUriComponentViews() {
    return mUriComponentViews;
  }

  
  public void setUriComponentViews(Map<String, String> pUriComponentViews) {
    mUriComponentViews = pUriComponentViews;
  }

  public Map<String,RequestDispatcher> getRequestDispatchers() {
    return mRequestDispatchers;
  }

  
  public void setRequestDispatchers(Map<String,RequestDispatcher> pRequestDispatchers) {
    mRequestDispatchers = pRequestDispatchers;
  }

}
